package com.wzcl.app.service.common;

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.*;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.*;
import com.alipay.api.response.*;
import com.wzcl.app.config.RabbitMqConfiguration;
import com.wzcl.app.dao.model.Orders;
import com.wzcl.app.model.common.BusinessException;
import com.wzcl.app.model.common.CodeMsg;
import com.wzcl.app.model.common.WZCL;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@Log4j2
@Service
@PropertySource({"classpath:application-config.properties"})
public class AliPayService implements MyPayService {
    public static final String TRADE_SUCCESS = "TRADE_SUCCESS"; //支付成功标识
    public static final String TRADE_FINISHED = "TRADE_FINISHED"; //支付成功标识
    public static final String TRADE_CLOSED = "TRADE_CLOSED";//交易关闭

    @Value("${aliPay.notifyUrl}")
    private String aliNotifyUrl;

    @Value("${aliPay.productCode}")
    private String productCode;

    @Value("${aliPay.timeExpress}")
    private String timeExpress;

    @Value("${aliPay.gatewayUrl}")
    private String gatewayUrl;

    @Value("${aliPay.appId}")
    private String appId;

    @Value("${aliPay.privateKey}")
    private String privateKey;

    @Value("${aliPay.publicKey}")
    private String publicKey;

    @Value("${aliPay.signType}")
    private String signType;

    @Value("${aliPay.charset}")
    private String charset;

    private static AlipayClient alipayClient = null;

    @Resource
    private AmqpTemplate amqpTemplate;

    @Override
    public String appPay(Orders orders, BigDecimal money, String name, String ip) {
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setBody("望子成龙网校订单");
        model.setSubject(name);
        model.setOutTradeNo(orders.getNo());
        model.setTimeoutExpress(timeExpress);
        model.setTotalAmount(money.setScale(2, BigDecimal.ROUND_DOWN).toString());
        model.setProductCode(productCode);
        request.setBizModel(model);
        request.setNotifyUrl(aliNotifyUrl);
        try {
            // 这里和普通的接口调用不同，使用的是sdkExecute
            AlipayTradeAppPayResponse response = getAliPayClient().sdkExecute(request);
            return response.getBody();
        } catch (AlipayApiException e) {
            throw new BusinessException(CodeMsg.PAY_OPERATE_FAIL, e.getErrMsg());
        }
    }

    //TODO 支付记录哈哈哈
    /*@Override
    public String query(PayRecord record) {
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        model.setOutTradeNo(record.getPayTradeAccount());
        model.setTradeNo(record.getOrderNo());
        request.setBizModel(model);
        try {
            AlipayTradeQueryResponse response = getAliPayClient().execute(request);
            return response.getBody();//就是orderString 可以直接给客户端请求，无需再做处理。
        } catch (AlipayApiException e) {
            throw new BusinessException(CodeMsg.PAY_OPERATE_FAIL, e.getErrMsg());
        }
    }*/

    //TODO 支付记录哈哈哈
    /*@Override
    public void refund(PayRecord record) {
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        AlipayTradeRefundModel model = new AlipayTradeRefundModel();
        model.setTradeNo(record.getTradeNo());
        model.setRefundAmount(record.getPay().setScale(2, BigDecimal.ROUND_DOWN).toString());
        request.setBizModel(model);
        try {
            AlipayTradeRefundResponse response = getAliPayClient().execute(request);
            log.info("支付宝退款信息:{}",JSON.toJSONString(response));
            if(response.isSuccess()){
                log.info("支付宝退款调用成功payRecord:{}",JSON.toJSONString(record));
            } else {
                throw new BusinessException(CodeMsg.PAY_OPERATE_FAIL,response.getSubMsg());
            }
        } catch (AlipayApiException e) {
            throw new BusinessException(CodeMsg.PAY_OPERATE_FAIL, e.getErrMsg());
        }
    }*/

    //TODO 支付记录哈哈哈
    /*@Override
    public String queryRefund(PayRecord record) {
        AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest();
        AlipayTradeFastpayRefundQueryModel model = new AlipayTradeFastpayRefundQueryModel();
        model.setOutTradeNo(record.getPayTradeAccount());
        model.setTradeNo(record.getOrderNo());
        model.setOutRequestNo(record.getOrderNo());
        request.setBizModel(model);
        try {
            AlipayTradeFastpayRefundQueryResponse response = getAliPayClient().execute(request);
            return response.getBody();
        } catch (AlipayApiException e) {
            throw new BusinessException(CodeMsg.PAY_OPERATE_FAIL, e.getErrMsg());
        }
    }*/


    @Override
    public void notify(HttpServletRequest request, HttpServletResponse response) {
        Map<String, String> params = convertRequestParamsToMap(request);
        if (check(params)){
            try {
                log.info("支付宝回调:{}",JSON.toJSONString(params));
                //支付宝的交易状态
                String trade_status = params.get("trade_status");
                // TODO 支付记录哈哈哈
                // 支付成功(支持退款/不支持退款返回值不同)
                /*PayRecord payRecord = new PayRecord();
                payRecord.setPayType(WZCL.PAY_TYPE.AlI_PAY);
                payRecord.setOrderNo(params.get("out_trade_no"));
                payRecord.setTradeNo(params.get("trade_no"));
                if (trade_status.equals(TRADE_SUCCESS)||trade_status.equals(TRADE_FINISHED)) {
                    payRecord.setPay(new BigDecimal(params.get("receipt_amount")));
                    payRecord.setPayTradeAccount(params.get("buyer_id"));
                    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    payRecord.setPayTime(format.parse(params.get("gmt_payment")));
                    payRecord.setPayState(WZCL.PAY_STATE.PAID);
                    payRecord.setSupportRefund(trade_status.equals(TRADE_SUCCESS));
                } else if (trade_status.equals(TRADE_CLOSED)){
                    //未付款交易超时关闭，或支付完成后全额退款
                    if(StringUtils.isNotBlank(params.get("out_biz_no"))){
                        payRecord.setPayState(WZCL.PAY_STATE.REFUNDED);
                        payRecord.setRefundTradeNo(params.get("out_biz_no"));
                    }else{
                        payRecord.setPayState(WZCL.PAY_STATE.PAY_FAIL);
                        log.error("支付宝回调业务订单关闭：{}", params);
                    }
                }else {
                    log.error("没有处理支付宝回调业务，支付宝交易状态：{}", trade_status);
                }*/
                //amqpTemplate.convertAndSend(RabbitMqConfiguration.DIRECT_QUEUE_PAID,JSON.toJSONString(payRecord));
                PrintWriter writer = response.getWriter();
                writer.write("success");
                writer.flush();
                writer.close();
            }catch (Exception e) {
                log.error("支付宝回调处理错误:{} \r\n 堆栈信息:{}",e.getMessage(),BusinessException.collectExceptionStackMsg(e));
            }
        }else{
            log.error("验签失败,不做处理：{}", JSON.toJSONString(params));
        }
    }

    @Override
    public void refundNotify(HttpServletRequest request, HttpServletResponse response) {
        //支付宝的退款异步回调时发到订单支付回调接口上的
    }


    @Override
    public boolean check(Map<String, String> params) {
        //验证签名 校验签名
        boolean signVerified = false;
        try {
            signVerified = AlipaySignature.rsaCheckV1(params, publicKey, charset, "RSA2");
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return signVerified;
    }


    // 将request中的参数转换成Map
    private static Map<String, String> convertRequestParamsToMap(HttpServletRequest request) {
        Map<String, String> retMap = new HashMap<String, String>();

        Set<Map.Entry<String, String[]>> entrySet = request.getParameterMap().entrySet();

        for (Map.Entry<String, String[]> entry : entrySet) {
            String name = entry.getKey();
            String[] values = entry.getValue();
            int valLen = values.length;

            if (valLen == 1) {
                retMap.put(name, values[0]);
            } else if (valLen > 1) {
                StringBuilder sb = new StringBuilder();
                for (String val : values) {
                    sb.append(",").append(val);
                }
                retMap.put(name, sb.toString().substring(1));
            } else {
                retMap.put(name, "");
            }
        }
        return retMap;
    }

    private synchronized AlipayClient getAliPayClient() {
        if (alipayClient == null) {
            alipayClient = new DefaultAlipayClient(gatewayUrl, appId, privateKey, "json", charset, publicKey, signType);
        }
        return alipayClient;
    }
}
